import type { DragSource } from '../drag/dragInterface';
import type { DropTarget } from '../drop/dropInterface';
import type { HandlerRegistry, SourceType, TargetType } from './interface';

import { HandlerRole } from './interface';
let nextUniqueId = 0;

class HandlerRegistryImpl implements HandlerRegistry {
  private types: Map<string, SourceType | TargetType> = new Map();
  private dragSources: Map<string, DragSource> = new Map();
  private dropTargets: Map<string, DropTarget> = new Map();

  public constructor() {}

  //--------source-------------
  public addSource(type: string, source: DragSource): string {
    const sourceId = this.addHandler(HandlerRole.SOURCE, type, source);
    return sourceId;
  }

  public removeSource(sourceId: string) {
    this.dragSources.delete(sourceId);
    this.types.delete(sourceId);
  }

  public getSource(sourceId: string): DragSource | undefined {
    return this.dragSources.get(sourceId)!;
  }

  public getSourceType(sourceId: string): SourceType | undefined {
    return this.types.get(sourceId) as SourceType;
  }

  //--------target-------------
  public addTarget: (accept: TargetType, target: DropTarget) => string = (
    accept,
    target,
  ) => {
    const targetId = this.addHandler(HandlerRole.TARGET, accept, target);
    return targetId;
  };

  public removeTarget: (targetId: string) => void = (targetId) => {
    this.dropTargets.delete(targetId);
    this.types.delete(targetId);
  };

  public getTarget: (targetId: string) => DropTarget | undefined = (
    targetId,
  ) => {
    return this.dropTargets.get(targetId);
  };

  public getTargetType: (targetId: string) => TargetType | undefined = (
    targetId,
  ) => {
    return this.types.get(targetId) as TargetType;
  };

  private addHandler(
    role: HandlerRole,
    type: SourceType | TargetType,
    handler: DragSource | DropTarget,
  ): string {
    let handlerId;
    if (role === HandlerRole.SOURCE) {
      handlerId = `S${nextUniqueId}`;
      this.dragSources.set(handlerId, handler as DragSource);
    } else if (role === HandlerRole.TARGET) {
      handlerId = `T${nextUniqueId}`;
      this.dropTargets.set(handlerId, handler as DropTarget);
    }
    if (!handlerId) {
      throw new Error('HandlerRegistryImpl--addHandler--请设置type属性');
    }
    this.types.set(handlerId, type);

    nextUniqueId += 1;
    return handlerId;
  }
}

export default HandlerRegistryImpl;
